
// 二、TypeScript 基础类型
// 2.1 Boolean 类型
// let isDone: boolean = false;
// // 2.2 Number 类型
// let count: number = 10;
// // String 类型
// let name1: string = "suizq";
// // 2.4 Array 类型
// let list: number[] = [1, 2, 3, 3];

// 2.5 Enum 类型
// 1.数字枚举
// enum Enum{ north ,east ,south,west};  
// 2.字符串枚举
// enum Direction {  NORTH = "NORTH",  SOUTH = "SOUTH",  EAST = "EAST",  WEST = "WEST",}
// enum Enum{ north="aa" ,east="bb" ,south="cc",west="dd"};
// let  myEnum:Enum=Enum.north;
// 3.异构枚举
// enum Enum {  A,  B,  C = "C",  D = "D",  E = 8,  F,}
// let  myEnum:Enum=Enum.A;
// console.log(myEnum);
// myEnum=Enum.C;
// console.log(myEnum);

// 2.6 Any 类型
// let value: any;value.foo.bar; // OKvalue.trim(); // OKvalue(); // OKnew value(); // OKvalue[0][1]; // OK
// 在许多场景下，这太宽松了。使用 any 类型，可以很容易地编写类型正确但在运行时有问题的代码。如果我们使用 any 类型，
// 就无法使用 TypeScript 提供的大量的保护机制。为了解决 any 带来的问题，TypeScript 3.0 引入了 unknown 类型。


// 2.7 Unknown 类型
// unknown 类型只能被赋值给 any 类型和 unknown 类型本身。直观地说，
// 这是有道理的：只有能够保存任意类型值的容器才能保存 unknown 类型的值。
// 毕竟我们不知道变量 value 中存储了什么类型的值。
// let value: unknown;
// ​value = true; // OK
// value = 42; // OK
// value = "Hello World"; // OK
// value = []; // OK
// value = {}; // OK
// value = Math.random; // OK
// value = null; // OK
// value = undefined; // OK
// value = new TypeError(); // OK
// value = Symbol("type"); // OK

// let value: unknown;
// let value1: unknown = value; 
// let value2:any=value;
// let value3:number=value; // Error
// let value4:object="2";   // Error


// OKlet value2: any = value; // OK
// let value3: boolean = value; // Error
// let value4: number = value; // Error
// let value5: string = value; // Error
// let value6: object = value; // Error
// let value7: any[] = value; // Error
// let value8: Function = value; // Error


// 2.8 Tuple 类型
// 元组是 TypeScript 中特有的类型，其工作方式类似于数组。
// type mytype= [string, boolean];
// let tupleType: mytype;
// tupleType = ["Semlinker", true];

// console.log(f1('11')('12'));

// 2.9 Void 类型

// type Mytype=()=>string;
// const MyFunction: (x: string) => (Mytype) = (x) => {

//     return () => { console.log(x); return x;};
// }
// let t: Mytype = MyFunction("11");
// t();

// type Mytype=()=>void;
// const MyFunction: (x: string) => (Mytype) = (x) => {
//     return () => { console.log(x);};
// }
// let t: Mytype = MyFunction("11");
// t();

// function MyFunction(): void {  console.log("This is my warning message");}
// let  MyFunction2: ()=>void = ()=> { console.log("This is my warning message");}


// 2.10 Null 和 Undefined 类型

// TypeScript 里，undefined 和 null 两者有各自的类型分别为 undefined 和 null。
//  let u: undefined = undefined;let n: null = null;
// 默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。
// 然而，如果你指定了--strictNullChecks 标记，null 和 undefined 只能赋值给 void 和它们各自的类型。

// 2.11 Never 类型

// never 类型表示的是那些永不存在的值的类型。 例如，never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

//  ​
//  // 返回never的函数必须存在无法达到的终点
//  function error(message: string): never {
//    throw new Error(message);
//  }
//  ​
//  function infiniteLoop(): never {
//    while (true) {}
//  }
// 在 TypeScript 中，可以利用 never 类型的特性来实现全面性检查，具体示例如下：

 ​
 type Foo = string | number;
 ​
 function controlFlowAnalysisWithNever(foo: Foo) {
   if (typeof foo === "string") {
     // 这里 foo 被收窄为 string 类型
   } else if (typeof foo === "number") {
     // 这里 foo 被收窄为 number 类型
   } else {
     // foo 在这里是 never
     const check: never = foo;
   }
 }
// 注意在 else 分支里面，我们把收窄为 never 的 foo 赋值给一个显示声明的 never 变量。如果一切逻辑正确，那么这里应该能够编译通过。但是假如后来有一天你的同事修改了 Foo 的类型：

//  type Foo = string | number | boolean;
// 然而他忘记同时修改 controlFlowAnalysisWithNever 方法中的控制流程，这时候 else 分支的 foo 类型会被收窄为 boolean 类型，导致无法赋值给 never 类型，这时就会产生一个编译错误。通过这个方式，我们可以确保

// controlFlowAnalysisWithNever 方法总是穷尽了 Foo 的所有可能类型。 通过这个示例，我们可以得出一个结论：使用 never 避免出现新增了联合类型没有对应的实现，目的就是写出类型绝对安全的代码。




// 三、TypeScript 断言
// 3.1 “尖括号” 语法
//  ​
//  let someValue: any = "this is a string";
//  let strLength: number = (<string>someValue).length;

// let myNmuber:Number =(<String>"abc").length;
// // 3.2 as 语法
// let myNmber2:Number=("abc" as string).length;

// 四、类型守卫

// 4.1 in 关键字
 ​
//  interface Admin {
//    name: string;
//    privileges: string[];
//  }
//  ​
//  interface Employee {
//    name: string;
//    startDate: Date;
//  }
//  ​
//  type UnknownEmployee = Employee | Admin;
//  ​
//  let emp1:UnknownEmployee={name:"szq",privileges:["aa","bb"],startDate:new Date()};
//  printEmployeeInformation(emp1);
//  function printEmployeeInformation(emp: UnknownEmployee) {
//    console.log("Name: " + emp.name);
//    if ("privileges" in emp) {
//      console.log("Privileges: " + emp.privileges);
//    }
//    if ("startDate" in emp) {
//      console.log("Start Date: " + emp.startDate);
//    }
//  }

// 4.2 typeof 关键字
 ​
//  function padLeft(value: string, padding: string | number) {
//    if (typeof padding === "number") {
//        return Array(padding + 1).join(" ") + value;
//    }
//    if (typeof padding === "string") {
//        return padding + value;
//    }
//    throw new Error(`Expected string or number, got '${padding}'.`);
//  }
// typeof 类型保护只支持两种形式：typeof v === "typename" 和 typeof v !== typename，"typename" 必须是 "number"， "string"， "boolean" 或 "symbol"。 但是 TypeScript 并不会阻止你与其它字符串比较，语言不会把那些表达式识别为类型保护。

// 4.3 instanceof 关键字
 ​
//  interface Padder {
//    getPaddingString(): string;
//  }
//  ​
//  class SpaceRepeatingPadder implements Padder {
//    constructor(private numSpaces: number) {}
//    getPaddingString() {
//      return Array(this.numSpaces + 1).join(" ");
//    }
//  }
//  ​
//  class StringPadder implements Padder {
//    constructor(private value: string) {}
//    getPaddingString() {
//      return this.value;
//    }
//  }
//  ​
//  let padder: Padder = new SpaceRepeatingPadder(6);
//  ​
//  console.log(typeof(padder))

// if (padder instanceof SpaceRepeatingPadder) {
// // padder的类型收窄为 'SpaceRepeatingPadder'
//     console.log("SpaceRepeatingPadder")
// }
// if (padder instanceof Padder) {
//     // padder的类型收窄为 'SpaceRepeatingPadder'
//         console.log("SpaceRepeatingPadder")
//     }

// interface Animal {
//     eat(): void;
// }
 
// class Dog implements Animal {
//     eat() {
//         console.log("Dog eats");
//     }
//     bark() {
//         console.log("Dog barks");
//     }
// }
 
// let dog = new Dog();
// console.log(dog instanceof Dog); // true
// console.log(dog instanceof Animal); // true

// 4.4 自定义类型保护的类型谓词
 ​
//  function isNumber2(x: any): x is number {
//    return typeof x === "number";
//  }
//  ​
//  function isString2(x: any): x is string {
//    return typeof x === "string";
//  }

//  https://blog.csdn.net/weixin_44198965/article/details/128973137
// Typescript - 类型守卫（typeof / in / instanceof / 自定义类型保护的类型谓词）通俗易懂详细教程

// // 判断参数是否为string类型, 返回布尔值
// function isString(s:unknown): s is string{
//     return typeof s === 'string'
//   }
  
// //   // 参数转为大写函数
// //   // 直接使用转大写方法报错, str有可能是其他类型
// //   function upperCase(str:unknown){
// //     str.toUpperCase()
// //     // 类型“unknown”上不存在属性“toUpperCase”。
// //   }
  
//   // 判断参数是否为字符串,是在调用转大写方法
//   function ifUpperCase(str:unknown){
  
//     if(isString(str)){
//       str.toUpperCase()
//       // (parameter) str: unknown
//       // 报错:类型“unknown”上不存在属性“toUpperCase”
//     }
//   }
  
function isFunction(obj: any): obj is FunctionConstructor {
    return typeof obj === 'function';
}

// 测试
const func = () => {};
const notFunc = 'hello';

console.log(isFunction(func)); // 输出 true
console.log(isFunction(notFunc)); // 输出 false

